import pandas as pd
import json
import os
from typing import Dict, List, Optional
from common_rules import DataRules

class TableMatcher:
    def __init__(self, config_path: str = "config.json", default_target_path: str = "templates\\ABC库存目标模板.xlsx"):
        """初始化表格匹配工具（Windows专用版）"""
        self.source_df: Optional[pd.DataFrame] = None
        self.target_df: Optional[pd.DataFrame] = None
        self.result_df: Optional[pd.DataFrame] = None
        self.base_dir = os.getcwd()
        self.default_target_path = default_target_path
        self.config = self._load_config(config_path)
        
        if "default_target_path" in self.config:
            self.default_target_path = self.config["default_target_path"]
            
        self.load_default_target_table()

    def _load_config(self, config_path: str) -> Dict:
        """加载配置文件（Windows专用路径处理）"""
        try:
            if not os.path.isabs(config_path):
                config_path = os.path.abspath(os.path.join(self.base_dir, config_path))
                
            with open(config_path, 'r', encoding='utf-8') as f:
                return json.load(f)
                
        except (FileNotFoundError, json.JSONDecodeError):
            return {
                "field_mapping": {}, 
                "default_target_path": "templates\\ABC库存目标模板.xlsx"
            }

    def load_default_target_table(self) -> bool:
        """自动加载默认目标表格（Windows环境）"""
        print(f"正在加载默认目标表格: {self.default_target_path}")
        
        if not os.path.isabs(self.default_target_path):
            abs_path = os.path.abspath(os.path.join(self.base_dir, self.default_target_path))
        else:
            abs_path = self.default_target_path
            
        if not os.path.exists(abs_path):
            print(f"\n===== 目标表格加载失败 =====")
            print(f"Windows绝对路径: {abs_path}")
            print("请执行以下步骤修复:")
            print(f"1. 在命令提示符中输入: md {os.path.dirname(abs_path)}")
            print(f"2. 将目标模板文件复制到该目录: {abs_path}")
            print("===========================\n")
            return False
            
        return self.load_target_table(abs_path)

    def load_source_table(self, file_path: str) -> bool:
        """加载待导入表格（Windows专用）"""
        try:
            if not os.path.isabs(file_path):
                file_path = os.path.abspath(os.path.join(self.base_dir, file_path))
                
            if file_path.endswith(('.xlsx', '.xls')):
                self.source_df = pd.read_excel(file_path)
            elif file_path.endswith('.csv'):
                self.source_df = pd.read_csv(file_path, encoding='gbk')
            else:
                print(f"错误: 不支持的文件格式 {os.path.splitext(file_path)[1]}")
                return False
                
            print(f"成功加载待导入表格: {file_path}，共 {len(self.source_df)} 行，{len(self.source_df.columns)} 列")
            return True
            
        except Exception as e:
            print(f"加载待导入表格失败: {str(e)}")
            return False

    def load_target_table(self, file_path: str) -> bool:
        """加载目标匹配表格（Windows专用）"""
        try:
            if not file_path.startswith(('C:\\', 'D:\\', 'E:\\')):
                file_path = os.path.abspath(file_path)
                
            if file_path.endswith(('.xlsx', '.xls')):
                self.target_df = pd.read_excel(file_path)
            elif file_path.endswith('.csv'):
                self.target_df = pd.read_csv(file_path, encoding='gbk')
            else:
                print(f"错误: 不支持的目标表格格式 {os.path.splitext(file_path)[1]}")
                return False
                
            if "检查结果" not in self.target_df.columns:
                self.target_df["检查结果"] = ""
                
            print(f"成功加载目标匹配表格: {file_path}，共 {len(self.target_df)} 行，{len(self.target_df.columns)} 列")
            return True
            
        except Exception as e:
            print(f"加载目标匹配表格失败: {str(e)}")
            return False

    def _map_field_name(self, field_name: str) -> str:
        """根据配置文件映射字段名"""
        if field_name in self.config.get("field_mapping", {}):
            return self.config["field_mapping"][field_name]
            
        for pattern, target in self.config.get("field_mapping", {}).items():
            if '*' in pattern:
                prefix, suffix = pattern.split('*', 1)
                if (not prefix or field_name.startswith(prefix)) and (not suffix or field_name.endswith(suffix)):
                    return target
                    
        return field_name

    def _apply_data_rules(self, df: pd.DataFrame) -> pd.DataFrame:
        """应用数据校验规则（使用公共规则模块）"""
        if "检查结果" not in df.columns:
            df["检查结果"] = ""
        
        # 1. 条形码强制转换为文本（无论内容如何）
        if "条形码" in df.columns:
            # 强制转换为字符串并保留原始格式
            df["条形码"] = df["条形码"].astype(str)
            # 处理空值（NaN转换为空字符串）
            df["条形码"] = df["条形码"].replace('nan', '')
            # 处理可能的小数点和科学计数法
            df["条形码"] = df["条形码"].str.replace(r'\.0$', '', regex=True)
            scientific_mask = df["条形码"].str.contains(r'^[+-]?\d+\.?\d*[eE][+-]?\d+$', na=False)
            if scientific_mask.any():
                df.loc[scientific_mask, "条形码"] = df.loc[scientific_mask, "条形码"].apply(
                    lambda x: f"{int(float(x)):d}" if '.' in x else f"{int(float(x)):d}"
                )
                df.loc[scientific_mask, "检查结果"] += "条形码已从科学计数法转换为文本; "
            # 检查空值并记录
            empty_mask = df["条形码"] == ""
            if empty_mask.any():
                df.loc[empty_mask, "检查结果"] += "条形码为空已处理; "
        
        # 2. 药品编码处理（仅对纯数字编码）
        df = DataRules.convert_scientific_notation(df, ['药品编码'])
        
        # 售价字段处理
        df = DataRules.validate_price_fields(df, fields=['总部售价', '门店售价'])
        
        # 3. 药品编码位数检查
        df = DataRules.validate_drug_code_length(df, field='药品编码', invalid_length=14)
        
        # 4. 药品名称处理（去除前导*）
        df = DataRules.clean_drug_name(df, field='药品')
        
        # 5. 厂家字段处理
        df = DataRules.fill_empty_manufacturer(df, field='厂家', fill_value='无')
        
        # 6. 国药准字类型处理
        df = DataRules.process_approval_number(df, approval_field='国药准字', type_field='类型')
        
        # 7. 拆零单位检查
        df = DataRules.check_split_unit(df, qty_field='拆零数量', unit_field='单位', split_unit_field='拆零单位')
        
        # 清理检查结果
        df["检查结果"] = df["检查结果"].str.strip("; ").str.replace(";;", ";")
        return df

    def match_tables(self, output_path: Optional[str] = None) -> bool:
        """执行表格匹配并输出结果"""
        if self.source_df is None or self.target_df is None:
            print("错误: 源表格或目标模板未加载")
            return False
            
        try:
            # 创建结果DataFrame，保留目标表格结构
            self.result_df = self.target_df.copy().iloc[0:0]  # 保留列名但清空数据
            
            # 获取字段映射关系
            target_fields = self.target_df.columns.tolist()
            source_fields = self.source_df.columns.tolist()
            field_mapping = {}
            
            # 1. 应用配置文件中的映射规则
            config_mapping = self.config.get("field_mapping", {})
            for source_field, target_field in config_mapping.items():
                if target_field in target_fields and target_field not in field_mapping:
                    if source_field in source_fields:
                        field_mapping[target_field] = source_field
            
            # 2. 按字段名完全匹配
            for field in target_fields:
                if field not in field_mapping and field in source_fields:
                    field_mapping[field] = field
            
            # 3. 执行数据映射
            mapped_rows = []
            for _, source_row in self.source_df.iterrows():
                target_row = {}
                
                # 填充映射字段
                for target_field, source_field in field_mapping.items():
                    target_row[target_field] = source_row[source_field]
                
                # 填充空值字段
                for field in target_fields:
                    if field not in target_row:
                        target_row[field] = None
                
                mapped_rows.append(target_row)
            
            # 创建临时DataFrame并应用数据规则
            temp_df = pd.DataFrame(mapped_rows)
            temp_df = self._apply_data_rules(temp_df)
            
            # 合并到结果DataFrame
            self.result_df = pd.concat([self.result_df, temp_df], ignore_index=True)
            
            # 保存结果
            if output_path:
                from file_utils import save_excel
                save_excel(self.result_df, output_path)
                print(f"表格匹配完成，结果已保存至: {output_path}")
                return True
                
            print(f"表格匹配完成，共处理 {len(self.result_df)} 行数据")
            return True
            
        except Exception as e:
            print(f"表格匹配失败: {str(e)}")
            return False